﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Brjnk.GpxExplorer.UI.Controls
{
    public class EnumPicker : Control
    {
        static EnumPicker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(EnumPicker), new FrameworkPropertyMetadata(typeof(EnumPicker)));
        }

        public EnumPicker()
        {
            this.Loaded += new RoutedEventHandler(EnumPicker_Loaded);
            Localization.LocalizationManager.Instance.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Instance_PropertyChanged);
        }

        void Instance_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == string.Empty)
                RebuildItemsList();
        }

        private void EnumPicker_Loaded(object sender, RoutedEventArgs e)
        {
            RebuildItemsList();
        }

        private Selector presenter;

        private ObservableCollection<EnumItem> items = new ObservableCollection<EnumItem>();

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (presenter != null) presenter.SelectionChanged -= new SelectionChangedEventHandler(presenter_SelectionChanged);
            presenter = this.GetTemplateChild("ItemsPresenter") as Selector;
            if (presenter != null)
            {
                presenter.ItemsSource = items;
                presenter.SelectionChanged += new SelectionChangedEventHandler(presenter_SelectionChanged);
            }
            RebuildItemsList();
        }

        private void presenter_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!IsLoaded) return;
            if (presenter.SelectedItem != null)
            {
                var item = presenter.SelectedItem as EnumItem;
                this.SetCurrentValue(ValueProperty, item.Value);
            }
        }

        private void RebuildItemsList()
        {
            items.Clear();
            if (EnumType != null && EnumType.IsEnum)
            {
                foreach (var item in GetItems(EnumType))
                {
                    items.Add(item);
                }
            }
            SetComboBox(this.Value);
        }

        private IEnumerable<EnumItem> GetItems(Type enumType)
        {
            if (Localize)
                return Enum.GetValues(enumType).Cast<Enum>().Select(v => new EnumItem(v, GetLocalizedString(v)));
            else
                return Enum.GetValues(enumType).Cast<Enum>().Select(v => new EnumItem(v, v.ToString()));
        }

        private string GetLocalizedString(Enum v)
        {
            string key = string.Format("$Enum${0}.{1}", v.GetType().ToString(), v.ToString());
            return Localization.LocalizationManager.Instance.GetString(key);
        }

        public Type EnumType
        {
            get { return (Type)GetValue(EnumTypeProperty); }
            set { SetValue(EnumTypeProperty, value); }
        }

        public static readonly DependencyProperty EnumTypeProperty =
            DependencyProperty.Register("EnumType", typeof(Type), typeof(EnumPicker), new UIPropertyMetadata(null, TypeChanged));

        public object Value
        {
            get { return GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(EnumPicker),
            new FrameworkPropertyMetadata(null, ValueChanged, CoerceValue) { BindsTwoWayByDefault = true });


        public bool Localize
        {
            get { return (bool)GetValue(LocalizeProperty); }
            set { SetValue(LocalizeProperty, value); }
        }

        public static readonly DependencyProperty LocalizeProperty =
            DependencyProperty.Register("Localize", typeof(bool), typeof(EnumPicker), new UIPropertyMetadata(true, LocalizeChanged));



        private static void TypeChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var target = sender as EnumPicker;
            if (target.IsLoaded == false) return;
            target.RebuildItemsList();
        }

        private static void LocalizeChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var target = (EnumPicker)sender;
            target.RebuildItemsList();
        }

        private static void ValueChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var target = sender as EnumPicker;
            target.SetComboBox(e.NewValue);
        }

        private static object CoerceValue(DependencyObject d, object baseValue)
        {
            return baseValue;
            //var target = d as EnumPicker;
            //if (target.IsLoaded == false) return baseValue;
            //if (baseValue == null) return null;
            //if (baseValue.GetType().IsEnum == false) return null;
            // return target.ChooseSelectedItem(baseValue as Enum);
        }

        private void SetComboBox(object value)
        {
            if (this.presenter == null) return;
            if (value == null) this.presenter.SelectedItem = null;
            else
            {
                var item = this.items.Where(i => Enum.Equals(value, i.Value)).FirstOrDefault();
                this.presenter.SelectedItem = item;
            }
        }
    }

    internal class EnumItem
    {
        public EnumItem(Enum value, string text)
        {
            this.Value = value;
            this.Text = text;
        }

        public Enum Value { get; private set; }

        public string Text { get; private set; }
    }
}